package com.lt.flashcard.model.service;

import java.util.HashSet;
import java.util.List;

import org.bson.types.ObjectId;

import com.google.code.morphia.dao.BasicDAO;
import com.google.code.morphia.query.Query;
import com.lt.flashcard.Utility;
import com.lt.flashcard.model.entity.Message;
import com.lt.flashcard.model.entity.User;

/**
 * Process the private message send from user to user
 * @author ocsen
 *
 */
public class MessageService {

	private BasicDAO<Message,ObjectId> _messageDao;
	/**
	 * Get DAO to interact with database
	 * @return
	 */
	private BasicDAO<Message,ObjectId> getMessageDAO() {
		if(_messageDao == null) {
			_messageDao = new BasicDAO<Message, ObjectId>(Message.class, Repository.getInstance().getDatastore());
		}
		return _messageDao;
	}
	
	/**
	 * Save a message to database
	 * @param message
	 */
	public void saveMessage(Message message) {
		BasicDAO<Message, ObjectId> srv = getMessageDAO();
		srv.save(message);
	}
	
	/**
	 * delete message
	 */
	public void deleteMessage(Message msg) {
		BasicDAO<Message, ObjectId> srv = getMessageDAO();
		srv.delete(msg);
	}
	
	/**
	 * Get a message by id
	 * @param id
	 * @return
	 */
	public Message getMessage(String id) {
		return getMessageDAO().get(new ObjectId(id));
	}
	
	/**
	 * Count unread message thread of a user
	 * @param userid
	 * @return
	 */
	public long countUnreadMessage(Long userid) {
		Query<Message> query = getMessageDAO().createQuery();
		query.field("owner").equal(userid);
		query.filter("unread >", 0);
		query.retrievedFields(true, "unread");
		long result = 0;
		for(Message m : query.asList())
			result += m.getUnread();
		return result;
	}
	
	/**
	 * Get message has been sent from user
	 * @param userid
	 * @return
	 */
	public List<Message> getMessageFromUser(Long userid) {
		Query<Message> query = getMessageDAO().createQuery();
		query.field("fromId").equal(userid);
		query.order("-created");
		return query.asList();
	}
	
	/**
	 * Get message sent to user
	 * @param userid
	 * @return
	 */
	public List<Message> getMessageToUser(Long userid) {
		Query<Message> query = getMessageDAO().createQuery();
		query.field("toId").equal(userid);
		query.order("-created");
		return query.asList();
	}
	
	/**
	 * Get all messages that relative to user
	 * @param userid
	 * @return
	 */
	public List<Message> getMessageOfUser(Long userid) {
		Query<Message> query = getMessageDAO().createQuery();
		query.field("owner").equal(userid);
		query.order("-created");
		return query.asList();
	}
	
	/**
	 * Get all messages in thread
	 * @param threadid
	 * @return
	 */
	public List<Message> getMessageInThread(String threadid) {
		Query<Message> query = getMessageDAO().createQuery();
		query.field("thread").equal(threadid);
		query.order("-created");
		return query.asList();
	}
	
	/**
	 * Create a new message from user to user
	 * @param fromUser
	 * @param toUser
	 * @param message
	 * @return
	 */
	public Message newMessage(User fromUser, User toUser, String message) {
		if(fromUser.getId() == null || toUser.getId() == null || Utility.isEmptyString(message))
			return null;
		
		Message msg = new Message();
		msg.setAvatar(fromUser.getAvatar());
		msg.setFromId(fromUser.getId());
		msg.setFromName(fromUser.getUsername());
		msg.setFromAvatar(fromUser.getAvatar());
		msg.setToId(toUser.getId());
		msg.setToAvatar(toUser.getAvatar());
		msg.setToName(toUser.getUsername());
		msg.setOwner(fromUser.getId());
		msg.addMessage(message, true);
		return msg;
	}
	
	/**
	 * Create a new message thread that send from user to other user
	 * @param fromUser
	 * @param toUser
	 * @param message
	 * @return the message of from user
	 */
	public Message sendNewMessage(User fromUser, User toUser, String message) {
		if(fromUser.getId() == null || toUser.getId() == null || Utility.isEmptyString(message))
			return null;
		
		Message msg = new Message();
		msg.setAvatar(fromUser.getAvatar());
		msg.setFromId(fromUser.getId());
		msg.setFromName(fromUser.getUsername());
		msg.setFromAvatar(fromUser.getAvatar());
		msg.setToId(toUser.getId());
		msg.setToAvatar(toUser.getAvatar());
		msg.setToName(toUser.getUsername());
		msg.setOwner(fromUser.getId());
		msg.addMessage(message, true);
		
		saveMessage(msg);
		msg.setThread(msg.getId().toString());
		saveMessage(msg);
		
		Message omsg = msg.clone();
		omsg.setOwner(toUser.getId());
		omsg.setUnread(1);
		saveMessage(omsg);
		
		NotificationService nsrv = Repository.getInstance().getNotificationService();
		nsrv.addNotificationPrivateMessage(fromUser, toUser);
		
		return msg;
	}
	
	/**
	 * User reply message
	 * @param msg
	 * @param content
	 */
	public void replyMessage(Message msg, String content) {
		if(Utility.isEmptyString(content))
			return;
		
		String thread = msg.getThread();
		List<Message> ls = getMessageInThread(thread);
		
		msg.addMessage(content, msg.getFromId().equals(msg.getOwner()));
		saveMessage(msg);
		
		HashSet<Long> p = new HashSet<Long>();
		p.add(msg.getFromId());
		p.add(msg.getToId());
		p.remove(msg.getOwner());
		
		for(Message m : ls) {
			if(p.contains(m.getOwner())) {
				m.addMessage(content, m.getFromId().equals(msg.getOwner()));
				saveMessage(m);
				p.remove(m.getOwner());
			}
		}
		
		if(p.size() > 0) {
			for(Long id : p) {
				Message nmsg = msg.clone();
				nmsg.getMessages().clear();
				nmsg.setUnread(0);
				nmsg.addMessage(content, p.equals(msg.getFromId()));
				nmsg.setOwner(id);
				saveMessage(nmsg);
			}
		}
	}
}
